# --------- 简介 ----------#
# ActiveDetector.py
# 本程序的工作原理是, 我们有一个具有特定容量的哈希表.
# 当一个数据包到达的时候, 如果哈希表中有和这个数据包具有
# 相同流标识符的流记录, 则我们将这个流记录的计数值增加1.
# 如果哈希表中没有和这样的流记录, 但是哈希表还没有满,
# 则我们为这个数据包在哈希表中新建一个流记录. 最后, 如果
# 哈希表中不存在一个这样的流记录, 并且哈希表已满, 则我们
# 将会替换最近最久不活跃的流.
# 赵宗义, xinshengzzy@foxmail.com, 2021.01.16
# ---------- #
from simulators.Buckets import ADBucket
from simulators.BaseSimulator import BaseSimulator
import heapq


class ActiveDetector(BaseSimulator):
    def __init__(self, 内存=1.0):
        super(ActiveDetector, self).__init__()
        self.容量 = int(内存*1024*1024/15.0)
        self.流集 = dict()
        self.小顶堆 = []

    def 处理数据包(self, 标识符, 时间戳):
        if 标识符 in self.流集:
            self.流集[标识符].increCnt(1, 时间戳)
        elif len(self.流集) <= self.容量:
            self.流集[标识符] = ADBucket(1, 时间戳)
            heapq.heappush(self.小顶堆, (时间戳, 标识符))
        else:
            self.更新流集(标识符, 时间戳)

    def 更新流集(self, 标识符, 时间戳):
        while True:
            临时间戳, 临标识符 = heapq.heappop(self.小顶堆)
            assert(临时间戳 <= self.流集[临标识符].getTs())
            if 临时间戳 < self.流集[临标识符].getTs():
                heapq.heappush(self.小顶堆, (self.流集[临标识符].getTs(), 临标识符))
            else:
                del self.流集[临标识符]
                self.流集[标识符] = ADBucket(1, 时间戳)
                heapq.heappush(self.小顶堆, (时间戳, 标识符))
                break

    def 在线流长查询(self, 标识符):
        if 标识符 in self.流集:
            return self.流集[标识符].getCnt()
        else:
            return 0
